// Copyright 2008-2009 BUGCOLLECT.COM
// Author: Remus Rusanu
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//                 http://bugcollect.com/terms
//

package com.bugcollect;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.UUID;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * This class stores the bugcollect.com response result of a report submission. 
 */
public class Result {

    private static class SAXResultParser extends DefaultHandler
    {
        public static final String tagNamespace = "http://bugcollect.com/schemas/result/v1.0";
        public static final String tagResult = "result";
        public static final String tagReportUUID = "report_uuid";
        public static final String tagReportId = "report_id";
        public static final String tagBucketId = "bucket_id";
        public static final String tagSourceId = "source_id";
        public static final String tagStatus = "status";
        public static final String tagResponse = "response";

        protected enum EParserState
        {
            NONE,
            RESULT,
        }


        private Result _result;
        private StringBuilder _currentBuilder;
        private EParserState _parserState;

        public SAXResultParser(Result result)
        {
            _result = result;
            _parserState = EParserState.NONE;
        }

        @Override
        public void startElement(
                String uri,
                String localName,
                String qName,
                Attributes attributes)
                throws SAXException
        {
            switch(_parserState)
            {
                case NONE:
                    if (0 == uri.compareTo(tagNamespace) &&
                        0 == localName.compareTo(tagResult))
                    {
                        _parserState = EParserState.RESULT;
                    }
                    break;
                case RESULT:
                    _currentBuilder = new StringBuilder();
                    break;
            }
        }


        @Override
        public void endElement(
                String uri,
                String localName,
                String qName)
                throws SAXException
        {
            do
            {
                if (_parserState != EParserState.RESULT)
                {
                    break;
                }
                if (0 != uri.compareTo(tagNamespace))
                {
                    break;
                }
                if (0 == localName.compareTo(tagReportUUID))
                {
                    _result._reportUuid = UUID.fromString(
                            _currentBuilder.toString());
                    break;
                }
                if (0 == localName.compareTo(tagReportId))
                {
                    _result._reportId = Integer.parseInt(
                            _currentBuilder.toString());
                    break;
                }
                if (0 == localName.compareTo(tagBucketId))
                {
                    _result._bucketId = Integer.parseInt(
                            _currentBuilder.toString());
                    break;
                }
                if (0 == localName.compareTo(tagSourceId))
                {
                    _result._sourceId = Integer.parseInt(
                            _currentBuilder.toString());
                    break;
                }
                if (0 == localName.compareTo(tagStatus))
                {
                    _result._status = EResultStatus.valueOf(
                            _currentBuilder.toString());
                    break;
                }
                if (0 == localName.compareTo(tagResponse))
                {
                    _result._response = _currentBuilder.toString();
                    break;
                }
            } while (false);
        }

        @Override
        public void characters(
                char buff[],
                int offset,
                int len)
                throws SAXException
        {
            if (_parserState != EParserState.RESULT)
            {
                return;
            }
            _currentBuilder.append(buff, offset, len);
        }

    }

    /**
     * Expicitly declared to force package only visibility
     */
    Result()
    {

    }

    private EResultStatus _status;

    /**
     * Gets the response status.
     */
    public EResultStatus getStatus()
    {
        return _status;
    }

    private int _reportId;
    /**
     *  Gets the ID assigned to the report by bugcollect.com.
     */
    public int getReportId()
    {
        return _reportId;
    }

    private int _bucketId;
    /**
     * Gets the ID assigned to the bucket into which the report was categorized.
     */
    public int getBucketId()
    {
        return _bucketId;
    }

    private int _sourceId;
    /**
     * Gets the ID assigned to the source which submitted the report.
     */
    public int getSourceId()
    {
        return _sourceId;
    }

    private UUID _reportUuid;
    /**
     * Gets the report global unique identifier.
     * If the submitted report did not have an UUID, bugcollect.com will
     * generate one and return it in the result.
     * @see com.bugcollect.Report#setUUID Report.setUUID
     */
    public UUID getReportUuid()
    {
        return _reportUuid;
    }

    private String _response;
    /**
     * Gets the response stream. This contains the response
     * set for the reported incident bucket at bugcollect.com.
     * For example the bucket can be marked at bugcollect.com to return 
     * a response that directs the end user to download a newer version
     * of the application. The application should parse the response and
     * display the appropiate message to the end user.
     */
    public Reader getResponse()
    {
        return new StringReader(_response);
    }

    /**
     * Internal parser of the response.
     * @param is
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws IOException
     */
    void parseXml (InputStream is)
            throws ParserConfigurationException, SAXException, IOException
    {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        factory.setValidating(false);
        factory.setNamespaceAware(true);
        SAXParser parser = factory.newSAXParser();

        parser.parse(is, new SAXResultParser(this));

    }
}
